#include <stdlib.h>
#include <string.h>

#include <windows.h>

#include "lib.h"
#include "libglob.h"
#include "bitmap.h"
#include "oldstylebitmap.h"
#include "screen.h"
#include "frame.h"

#include "resmgr.h"
#include "resfile.h"
#include "resentry.h"
#include "pftblt.h"

#define TRANSBYTE	0x00
/*
// Private variables
//
static struct _BmpHeaderAndPal
{
	BITMAPINFOHEADER  Header;
	RGBQUAD           aColorTable[256];
} BmpHeaderAndPal =
{
	sizeof(BITMAPINFOHEADER),
	50, 50,
	1, 8,
	BI_RGB,
	0, 0, 0, 256, 256
};

// Private functions
//

pOldCBitmap
newOldCBitmap(char * Name, uint32 Group)
{
	pOldCBitmap This = NULL;
	void *data;


	data = CResMgrGetResource(gResMgr, Name, Group);
	if (data)
	{
		This = (pOldCBitmap)malloc(sizeof(OldCBitmap));

		if (This)
		{
			OldCBitmapBuffer * buffer = (OldCBitmapBuffer *)data;

			if (!OldCBitmapConstruct(This, buffer->cSize.x, buffer->cSize.y, 
				(char *)((uint32)data + sizeof(OldCBitmapBuffer)),
				CFrameDC(CScreenGetFrame(gScreen))))
			{
				free(This);
				This = (pOldCBitmap)0;
			}
		}
		CResMgrReleaseResource(gResMgr, data);
	}
	else
		DEBUGMSG(("newOldCBitmap(): %s not found in resource file.", Name));

	return This;
}

pOldCBitmap	
newOldCBitmapFrame(int32 Width, int32 Height, HDC BmpDC)
{
	pOldCBitmap This = (pOldCBitmap)malloc(sizeof(OldCBitmap));
	if (This && !OldCBitmapConstruct(This, Width, Height, (char *)0, BmpDC))
	{
		free(This);
		This = 0;
	}
	return This;
}

pOldCBitmap
newOldCBitmapBlank(int32 Width, int32 Height)
{
	pOldCBitmap This = newOldCBitmapFrame(Width, Height, 
		CFrameDC(CScreenGetFrame(gScreen)));
	if (This)
		OldCBitmapClear(This);
	return This;
}
void		
deleteOldCBitmap(pOldCBitmap This)
{
	if (This)
	{
		OldCBitmapDestruct(This);
		free(This);
	}
}

bool8
OldCBitmapConstruct(pOldCBitmap This, int32 Width, int32 Height, char *Bits,
	HDC BmpDC)
{
	int32 line;

	BmpHeaderAndPal.Header.biWidth = Width;
	BmpHeaderAndPal.Header.biHeight = -Height;
	BmpHeaderAndPal.Header.biSizeImage = ((((Width * 8) + 31) & ~31) >> 3) *
		Height;

	This->chBmp = CreateDIBSection(BmpDC, 
		(BITMAPINFO *)&BmpHeaderAndPal, DIB_RGB_COLORS, &This->cBits,
		(HANDLE)0, 0);
	if (!This->chBmp)
		return false;

	This->cSize.x = Width;
	This->cSize.y = Height;
	This->cRowBytes = BmpHeaderAndPal.Header.biWidth *
		BmpHeaderAndPal.Header.biBitCount;
	This->cRowBytes = ((This->cRowBytes + 31) & (~31)) >> 3;
	This->cUpsideDown = BmpHeaderAndPal.Header.biHeight >= 0;

	if (Bits)
	{
		if (This->cUpsideDown)
			for (line = 0; line < Height; line++)
				memcpy((char *)This->cBits + (Height-1- line) * This->cRowBytes,
					Bits + line * Width,
					Width);
		else
			for (line = 0; line < Height; line++)
				memcpy((char *)This->cBits + line * This->cRowBytes,
					Bits + line * Width,
					Width);
	}

	return true;
}

void
OldCBitmapDestruct(pOldCBitmap This)
{
	if (This->chBmp)
	{
		DeleteObject(This->chBmp);
		This->chBmp = (HBITMAP)0;
		This->cBits = (uint8 *)0;
		This->cRowBytes = 0;
	}
}

void	
OldCBitmapNewPalette(LOGPALETTE *pLogPal)
{
	int32 i;

	for (i = 0; i < pLogPal->palNumEntries; i++)
	{
		BmpHeaderAndPal.aColorTable[i].rgbRed = pLogPal->palPalEntry[i].peRed;
		BmpHeaderAndPal.aColorTable[i].rgbGreen=pLogPal->palPalEntry[i].peGreen;
		BmpHeaderAndPal.aColorTable[i].rgbBlue =pLogPal->palPalEntry[i].peBlue;
		BmpHeaderAndPal.aColorTable[i].rgbReserved = 0;
	}
}

void
OldCBitmapClear(pOldCBitmap This)
{
	memset(OldCBitmapBits(This), TRANSBYTE,
		OldCBitmapHeight(This) * OldCBitmapRowBytes(This));
}

void	
OldCBitmapClearRect(pOldCBitmap This, int32 Left, int32 Top,
	int32 Right, int32 Bottom)
{
	OldCBitmapFillRect(This, Left, Top, Right, Bottom, TRANSBYTE);
}

void	
OldCBitmapFillRect(pOldCBitmap This, int32 Left, int32 Top,
			int32 Right, int32 Bottom, uint8 Color)
{
	int32 line;

	if (Right < 0 || Left >= OldCBitmapWidth(This) ||
		Bottom < 0 || Top >= OldCBitmapHeight(This)) return;
	if (Left < 0) Left = 0;
	if (Right >= OldCBitmapWidth(This)) Right = OldCBitmapWidth(This) - 1;
	if (Top < 0) Top = 0;
	if (Bottom >= OldCBitmapHeight(This)) Bottom = OldCBitmapHeight(This) - 1;

	if (OldCBitmapUpsideDown(This))
		for (line = Top; line <= Bottom; line++)
			memset(OldCBitmapBits(This) +
					(OldCBitmapHeight(This) - 1 - line) *
					OldCBitmapRowBytes(This) + Left,
				Color,
				Right - Left + 1);
	else
		for (line = Top; line <= Bottom; line++)
			memset(OldCBitmapBits(This) + line *
					OldCBitmapRowBytes(This) + Left,
				Color,
				Right - Left + 1);
}

void	
OldCBitmapBitmapBlt(pOldCBitmap This, int32 DestX, int32 DestY, pOldCBitmap Src)
{
	long height;
	uint8 *pSrc;

	if (!Src || (Src && !OldCBitmapHBmp(Src)))
		return;

	height = OldCBitmapHeight(Src);

	if (OldCBitmapUpsideDown(Src))
		pSrc = OldCBitmapBits(Src) + (OldCBitmapHeight(Src) - 1) *
			OldCBitmapRowBytes(Src);
	else
		pSrc = OldCBitmapBits(Src);

	if (DestY < 0)
	{
		height += DestY;
		if (OldCBitmapUpsideDown(Src))
			pSrc += DestY * OldCBitmapRowBytes(Src);
		else
			pSrc -= DestY * OldCBitmapRowBytes(Src);
		DestY = 0;
	}
	if (height > 0)
	{
		if (height > OldCBitmapHeight(This) - DestY)
			height = OldCBitmapHeight(This) - DestY; 

		if (OldCBitmapUpsideDown(This))
		{
			CFrameBitmapBlast(
				OldCBitmapBits(This) + (OldCBitmapHeight(This) - DestY - 1) *
					OldCBitmapRowBytes(This) + DestX,
				pSrc,
				height,
				OldCBitmapWidth(Src),
				-OldCBitmapRowBytes(This) - OldCBitmapWidth(Src),
				-OldCBitmapRowBytes(Src) - OldCBitmapWidth(Src));
		}
		else
		{
			CFrameBitmapBlast(
				OldCBitmapBits(This) + DestY * OldCBitmapRowBytes(This) + DestX,
				pSrc,
				height,
				OldCBitmapWidth(Src),
				OldCBitmapRowBytes(This) - OldCBitmapWidth(Src),
				OldCBitmapRowBytes(Src) - OldCBitmapWidth(Src));
		}
	}
}

void			
OldCBitmapBitmapBltSection(pOldCBitmap This, int32 dx, int32 dy,
	int32 sx, int32 sy, int32 sw, int32 sh, pOldCBitmap Src)
{
	if (!Src || (Src && !OldCBitmapHBmp(Src)) ||
		!OldCBitmapBits(Src) || sx < 0 || sy < 0 ||
		dx > OldCBitmapWidth(This) || dy > OldCBitmapHeight(This))
		return;
	if (sw > OldCBitmapWidth(Src))
		sw = OldCBitmapWidth(Src);
	if (sh > OldCBitmapHeight(Src))
		sh = OldCBitmapHeight(Src);

	if (dx < 0)
	{
		sx -= dx;
		sw += dx;
		dx = 0;
	}
	if (dy < 0)
	{
		sy -= dy;
		sh += dy;
		dy = 0;
	}

	if (sx > OldCBitmapWidth(Src) || sy > OldCBitmapHeight(Src) || sw < 0 || sh < 0)
		return;

	if (sw > OldCBitmapWidth(This) - dx)
		sw = OldCBitmapWidth(This) - dx;
	if (sh > OldCBitmapHeight(This) - dy)
		sh = OldCBitmapHeight(This) - dy;

	if (OldCBitmapUpsideDown(This))
	{
		CFrameBitmapBlast(
			OldCBitmapBits(This) + (OldCBitmapHeight(This) - dy - 1) *
				OldCBitmapRowBytes(This) + dx,
			OldCBitmapBits(Src) + (OldCBitmapHeight(Src) - sy - 1) *
				OldCBitmapRowBytes(Src) + sx,
			sh,
			sw,
			-OldCBitmapRowBytes(This) - sw,
			-OldCBitmapRowBytes(Src) - sw);
	}
	else
	{
		CFrameBitmapBlast(
			OldCBitmapBits(This) + dy * OldCBitmapRowBytes(This) + dx,
			OldCBitmapBits(Src) + sy * OldCBitmapRowBytes(Src) + sx,
			sh,
			sw,
			OldCBitmapRowBytes(This) - sw,
			OldCBitmapRowBytes(Src) - sw);
	}
}

void	
OldCBitmapTransparentBitmapBlt(pOldCBitmap This, int32 DestX, int32 DestY,
	pOldCBitmap Src)
{
	long height;
	uint8 *pSrc;

	if (!Src || (Src && !OldCBitmapHBmp(Src)))
		return;

	height = OldCBitmapHeight(Src);
	if (OldCBitmapUpsideDown(Src))
		pSrc = OldCBitmapBits(Src) + (OldCBitmapHeight(Src) - 1) *
			OldCBitmapRowBytes(Src);
	else
		pSrc = OldCBitmapBits(Src);

	if (DestY < 0)
	{
		height += DestY;
		if (OldCBitmapUpsideDown(Src))
			pSrc += DestY * OldCBitmapRowBytes(Src);
		else
			pSrc -= DestY * OldCBitmapRowBytes(Src);
		DestY = 0;
	}
	if (height > 0)
	{
		if (height > OldCBitmapHeight(This) - DestY)
			height = OldCBitmapHeight(This) - DestY; 

		if (OldCBitmapUpsideDown(This))
		{
			CFrameTransBitmapBlast(
				OldCBitmapBits(This) + (OldCBitmapHeight(This) - DestY - 1) *
					OldCBitmapRowBytes(This) + DestX,
				pSrc,
				height,
				OldCBitmapWidth(Src),
				-OldCBitmapRowBytes(This) - OldCBitmapWidth(Src),
				-OldCBitmapRowBytes(Src) - OldCBitmapWidth(Src));
		}
		else
		{
			CFrameTransBitmapBlast(
				OldCBitmapBits(This) + DestY * OldCBitmapRowBytes(This) + DestX,
				pSrc,
				height,
				OldCBitmapWidth(Src),
				OldCBitmapRowBytes(This) - OldCBitmapWidth(Src),
				OldCBitmapRowBytes(Src) - OldCBitmapWidth(Src));
		}
	}
}

void			
OldCBitmapTransparentBitmapBltSection(pOldCBitmap This, int32 dx, int32 dy,
	int32 sx, int32 sy, int32 sw, int32 sh, pOldCBitmap Src)
{
	if (!Src || (Src && !OldCBitmapHBmp(Src)) ||
		!OldCBitmapBits(Src) || sx < 0 || sy < 0 ||
		dx > OldCBitmapWidth(This) || dy > OldCBitmapHeight(This))
		return;
	if (sw > OldCBitmapWidth(Src))
		sw = OldCBitmapWidth(Src);
	if (sh > OldCBitmapHeight(Src))
		sh = OldCBitmapHeight(Src);

	if (dx < 0)
	{
		sx -= dx;
		sw += dx;
		dx = 0;
	}
	if (dy < 0)
	{
		sy -= dy;
		sh += dy;
		dy = 0;
	}

	if (sx > OldCBitmapWidth(Src) || sy > OldCBitmapHeight(Src) || sw < 0 || sh < 0)
		return;

	if (sw > OldCBitmapWidth(This) - dx)
		sw = OldCBitmapWidth(This) - dx;
	if (sh > OldCBitmapHeight(This) - dy)
		sh = OldCBitmapHeight(This) - dy;

	if (OldCBitmapUpsideDown(This))
	{
		CFrameTransBitmapBlast(
			OldCBitmapBits(This) + (OldCBitmapHeight(This) - dy - 1) *
				OldCBitmapRowBytes(This) + dx,
			OldCBitmapBits(Src) + (OldCBitmapHeight(Src) - sy - 1) *
				OldCBitmapRowBytes(Src) + sx,
			sh,
			sw,
			-OldCBitmapRowBytes(This) - sw,
			-OldCBitmapRowBytes(Src) - sw);
	}
	else
	{
		CFrameTransBitmapBlast(
			OldCBitmapBits(This) + dy * OldCBitmapRowBytes(This) + dx,
			OldCBitmapBits(Src) + sy * OldCBitmapRowBytes(Src) + sx,
			sh,
			sw,
			OldCBitmapRowBytes(This) - sw,
			OldCBitmapRowBytes(Src) - sw);
	}
}
*/